package light.head.framework.base;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import light.head.constant.Sys;
import light.head.enm.RESULT;
import light.head.framework.entity.PageBean;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

/**
 * @author 简航 E_mail:janhang@126.com
 * @version 创建时间：May 28, 2008 3:46:13 PM 类说明
 */
@Repository
public class BaseDAO<M, CODE extends Serializable> extends HibernateDaoSupport {
	
	private final static String CAP_ORDER_BY = "ORDER BY";
	private final static String LOW_ORDER_BY = "order by";
	
	private Class<M> mc;

	@SuppressWarnings("unchecked")
	public BaseDAO() {
		if (mc == null) 
			mc = (Class<M>)((ParameterizedTypeImpl)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

	/**
	 * 分页查询SQL
	 * @param	查询sql语句
	 * @param	分页信息对象
	 * @param	sql语句所用到的参数
	 * @param	countSql需要的参数
	 * @return	是否查询成功
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected RESULT queryToPageBean(final PageBean pageBean, 
						final String sql, final List<Object> parm, 
						final String countSql, final List<Object> countParm) {
		
		return getHibernateTemplate().execute(new HibernateCallback() {
			public RESULT doInHibernate(Session session) throws HibernateException, SQLException {
				SQLQuery query = session.createSQLQuery(sql);
				query.setFirstResult((pageBean.getPage() - 1) * pageBean.getPageSize());
				query.setMaxResults(pageBean.getPageSize());

				for (int i = 0; i < parm.size(); i ++) {
					query.setParameter(i, parm.get(i));
				}
				pageBean.setResultList(query.list());
				
				/** 获取符合条件的总数 */
				query = session.createSQLQuery(countSql);
				for (int i = 0; i < countParm.size(); i ++)
					query.setParameter(i, countParm.get(i));
				pageBean.setTotal(Long.parseLong(query.uniqueResult().toString()));
				
				/** 计算pageBean的其他信息 */
				pageBean.compute();
				
				return RESULT.SUCCESS;
			}
		});
	}
	
	/**
	 * 分页查询HQL
	 * @param	查询hql语句
	 * @param	分页信息对象
	 * @param	查询hql语句所用到的参数
	 * @return	是否查询成功
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected RESULT findToPageBean(final String hql, final PageBean pageBean, final List<Object> list) {
		return getHibernateTemplate().execute(new HibernateCallback() {
			public RESULT doInHibernate(Session session) throws HibernateException, SQLException {
				Query query = session.createQuery(hql.toString());
				query.setFirstResult(pageBean.getStart());
				query.setMaxResults(pageBean.getPageSize());

				for (int i = 0; null != list && i < list.size(); i ++) {
					query.setParameter(i, list.get(i));
				}
				
				/** 获取需要显示的结果和符合条件的总数 */
				pageBean.setResultList(query.list());
				
				String countHql = "SELECT COUNT(*) ";
				if (hql.indexOf(LOW_ORDER_BY) != -1)
					countHql += hql.substring(0, hql.indexOf(LOW_ORDER_BY) - 1);
				else if (hql.indexOf(CAP_ORDER_BY) != -1)
					countHql += hql.substring(0, hql.indexOf(CAP_ORDER_BY) - 1);
				
				if (null != list && 0 < list.size())
					pageBean.setTotal((Long) getHibernateTemplate().find(countHql, list.toArray()).listIterator().next());
				else 
					pageBean.setTotal((Long) getHibernateTemplate().find(countHql).listIterator().next());

				/** 计算pageBean的其他信息 */
				pageBean.compute();
				return RESULT.SUCCESS;
			}
		});
	}
	
	/**
	 * 根据HQL及参数查询结果（例：FROM Test t WHERE t.code = ?）“?”就为之后传入的参数
	 * @param	HQL
	 * @param	参数
	 * @return	查询结果
	 */
	@SuppressWarnings("unchecked")
	protected <X>List<X> find(String hql, Object...values) {
		return getHibernateTemplate().find(hql, values);
	}
	/**
	 * 该方法是为了解决传入两个参数为Integer情况
	 * @param hql
	 * @param values
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected <X>List<X> findI(String hql, Object...values) {
		return getHibernateTemplate().find(hql, values);
	}
	/**
	 * 根据HQL及参数获取查询结果（可指定从第几条开始获取，共获取多少条记录）
	 * 未验证是否可参与事务
	 * @param	HQL
	 * @param	从第几条开始
	 * @param	共获取多少条记录
	 * @param	参数数组（hql中的“?”号）
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected <X>List<X> find(final String hql, final Integer first, final Integer total, final Object...parms) {
		List<X> list = getHibernateTemplate().executeFind(new HibernateCallback() { // 实现HibernateCallback接口必须实现的方法
			public List<X> doInHibernate(Session session) throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				
				if (null != first)
					query.setFirstResult(first);
				if (null != total)
					query.setMaxResults(total);
				
				if (null != parms && parms.length > 0)
					for (int i = 0; i < parms.length; i ++){
						query.setParameter(i, parms[i]);
					}
				List<X> list = query.list();
				return list;
			}
		});
		return list;
	}
	
	/**
	 * 执行自定义查询SQL
	 * @param	查询sql语句
	 * @param	查询sql语句所用到的参数
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected <X>List<X> query(final String sql, final Integer first, final Integer total, final Object...parms) {
		List<X> list = getHibernateTemplate().executeFind(new HibernateCallback() { // 实现HibernateCallback接口必须实现的方法
			public Object doInHibernate(Session session) throws HibernateException, SQLException {
				SQLQuery query = session.createSQLQuery(sql);

				if (null != first)
					query.setFirstResult(first);
				if (null != total)
					query.setMaxResults(total);
				
				if (null != parms && parms.length > 0)
					for (int i = 0; i < parms.length; i ++)
						query.setParameter(i, parms[i]);
				
				List<X> list = query.list();
				return list;
			}
		});
		return list;
	}
	
	/**
	 * 执行HQL语句
	 * 未验证是否可参与事务
	 * @param	HQL
	 * @param	参数
	 * @return	该语句影响的行数
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected Integer execute(final String hql, final Object...values) {
		Integer result = getHibernateTemplate().execute(new HibernateCallback() {
			public Integer doInHibernate(Session session) throws HibernateException {
				Query q = session.createQuery(hql);
				for (int i = 0; i < values.length; i ++) {
					q.setParameter(i, values[i]);
				}
				return q.executeUpdate();
			}
		});
		return result;
	}
	
	/**
	 * 执行SQL语句
	 * 未验证是否可参与事务
	 * @param	sql
	 * @param	参数
	 * @return	该语句影响的行数
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected Integer executeSql(final String sql, final Object...values) {
		Integer result = getHibernateTemplate().execute(new HibernateCallback() {
			public Integer doInHibernate(Session session) throws HibernateException {
				Query q = session.createSQLQuery(sql);
				for (int i = 0; i < values.length; i ++) {
					q.setParameter(i, values[i]);
				}
				return q.executeUpdate();
			}
		});
		
		return result;
	}

	/**
	 * 根据HQL及该语句用到的参数，获取一个对象
	 * @param	HQL
	 * @param	参数数组
	 */
	@SuppressWarnings("unchecked")
	protected Object get(String hql, Object...values) {
		List<Object> list = getHibernateTemplate().find(hql, values);
		if (null != list && list.size() > 0)
			return list.get(0);
		return null;
	}
	
	/**
	 * 根据code获取DAO中指定的对象
	 * @param	code
	 */
	public M get(final CODE code) {
		if (null == code)
			return null;
		M m = getHibernateTemplate().get(mc, code);
		return  m;
	}
	
	/**
	 * 根据code获取指定类型的对象
	 * @param	对象类型
	 * @param	code
	 */
	@SuppressWarnings("rawtypes")
	public Object get(Class c, Integer code) {
		return getHibernateTemplate().get(c.getName(), (Serializable)code);
	}
	
	/**
	 * 添加参数指定的对象
	 * @param	要添加的对象
	 */
	public RESULT add(Object model) {
		if (null == model)
			return RESULT.PARAMETER_ERROR;
		getHibernateTemplate().save(model);
		return RESULT.SUCCESS;
	}

	/**
	 * 根据code删除DAO中泛型指定的对象
	 * @param	code
	 */
	public RESULT del(final CODE code) {
		if (null == code)
			return RESULT.PARAMETER_ERROR;
		M model = get(code);
		if (null == model)
			return RESULT.NOT_FIND;
		return del(model);
	}

	/**
	 * 删除参数所指定的对象
	 * @param	要删除的对象
	 */
	public RESULT del(Object model) {
		if (null == model)
			return RESULT.PARAMETER_ERROR;
		getHibernateTemplate().delete(model);
		return RESULT.SUCCESS;
	}
	
	/**
	 * 根据code删除指定类型的对象
	 * @param	要删除的对象类型
	 * @param	code
	 */
	@SuppressWarnings("rawtypes")
	public RESULT del(Class c, Integer code) {
		getHibernateTemplate().delete(c.getName(), code);
		return RESULT.SUCCESS;
	}
	
	/**
	 * 删除数组中的所有对象
	 * @param	要删除的对象数组
	 */
	public RESULT delAll(List<M> list) {
		getHibernateTemplate().deleteAll(list);
		return RESULT.SUCCESS;
	}
	
	/**
	 * 更新参数中指定的对象
	 * @param	要更新的对象
	 */
	public RESULT upd(Object model) {
		getHibernateTemplate().update(model);
		return RESULT.SUCCESS;
	}

	/**
	 * 更新或添加参数中指定的对象，如果是更新，该对象的主键必须赋值
	 * @param	要更新或添加的对象
	 */
	public RESULT sou(Object model) {
		if (null == model)
			return RESULT.PARAMETER_ERROR;
		getHibernateTemplate().saveOrUpdate(model);
		return RESULT.SUCCESS;
	}
	
	/**
	 * 修改或添加数组中的所有对象
	 * @param	要修改或添加的对象数组
	 */
	public RESULT souAll(List<M> list) {
		getHibernateTemplate().saveOrUpdateAll(list);
		return RESULT.SUCCESS;
	}

	/**
	 * 执行复杂的(hibernate不能执行的)sql语句
	 * 不能加到事务中，因为该方法执行完将会把当前session关闭
	 * @param 要执行的sql语句
	 * @return 集合框架,List+Map
	 * @author 简航 创建日期 Dec 22, 2008 10:22:11 AM
	 */
	protected List<Hashtable<String, Object>> getListHashtableBySql(String sql) {
		List<Hashtable<String, Object>> list = null;
		try {
			Connection conn = null;
			list = new ArrayList<Hashtable<String, Object>>();
			conn = SessionFactoryUtils.getDataSource(getHibernateTemplate().getSessionFactory()).getConnection();
			PreparedStatement stsm = conn.prepareStatement(sql);
			ResultSet rs = stsm.executeQuery();
			ResultSetMetaData metaData = rs.getMetaData();
			String[] headList = new String[metaData.getColumnCount()];
			for (int i = 0; i < metaData.getColumnCount(); i++) {
				headList[i] = metaData.getColumnName(i + 1);
			}
			Hashtable<String, Object> table = null;
			while (rs.next()) {
				table = new Hashtable<String, Object>();
				for (int i = 0; i < headList.length; i++) {
					table.put(headList[i], (rs.getObject(i + 1) != null ? rs
							.getString(i + 1) : ""));
				}
				list.add(table);
			}

			rs.close();
			stsm.close();
			conn.close();
		} catch (SQLException e) {
			System.out.println("在BaseDAO中进行查询时发生错误, 有可能是因为并发数量太大所致. Exception: " + e.toString());
			return null;
		}
		return list;
	}
	
	/**
	 * 判断字符串是否不为null和空字符串
	 * @return	为null或空字符串就返回false，否则true
	 */
	protected boolean isNotNull(String str) {
		return null == str || Sys.NONE.equals(str) ? false : true;
	}
	
	@Autowired  
    public void setSessionFactoryOverride(SessionFactory sessionFactory) {   
		super.setSessionFactory(sessionFactory);   
	}
	
	@SuppressWarnings("unchecked" )
	public M getUniqueResult(final String hql, final Object... args) {
		return (M) getHibernateTemplate().execute(new HibernateCallback<M>() {
			public M doInHibernate(Session session) throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				for (int i = 0; i < args.length; i++) {
					query.setParameter(i, args[i]);
				}
				return (M) query.uniqueResult();
			}
		});
	}
	
	@SuppressWarnings("unchecked")
	public <X> X getOneColumn(final String sql, final Object... args) {
		return (X) getHibernateTemplate().execute(new HibernateCallback<X>() {
			public X doInHibernate(Session session) throws HibernateException, SQLException {
				Query query = session.createSQLQuery(sql);
				for (int i = 0; i < args.length; i++) {
					query.setParameter(i, args[i]);
				}
				List<X> list = query.list();
				return list != null && list.size() > 0 ? list.get(0) : null;
			}
		});
	}
	
	@SuppressWarnings("unchecked")
	public <X> List<X> queryToList(final String sql, final Object... args) {
		return (List<X>) this.getHibernateTemplate().executeFind(new HibernateCallback<List<X>>() {
			@Override
			public List<X> doInHibernate(Session session) throws HibernateException,
					SQLException {
				SQLQuery sqlQuery = session.createSQLQuery(sql);
				for (int i = 0; i < args.length; i++) {
					sqlQuery.setParameter(i, args[i]);
				}
				List<X> list = sqlQuery.list();
				return list;
			}
		});
	}
}
